
/*
 * ----------------------------------------------------------------
 *                             WIDGET
 * ----------------------------------------------------------------
 */


/**
 * @class
 */
flyui.flyatlas.Widget = function( service, renderer ) {
    
    // do initialisation
    this._init(service, renderer);
    
};

/** @private */
flyui.flyatlas.Widget.prototype._controller = null;

/**
 * @private
 * @type flyui.mvcutils.GenericModel2
 */ 
flyui.flyatlas.Widget.prototype._model = null;

/**
 * @private
 */
flyui.flyatlas.Widget.prototype._renderer = null;

/**
 * @private
 */
flyui.flyatlas.Widget.prototype._service = null;

/**
 * @private
 * TODO doc me
 */
flyui.flyatlas.Widget.prototype._init = function(service, renderer) {
    
    this._service = service;
    this._renderer = renderer;
    
    // create a model
    this._model = new flyui.mvcutils.GenericModel2();
    this._model.setDefinition(flyui.flyatlas.Widget.modelDefinition);
    
    // instantiate the controller
    this._controller = new flyui.flyatlas.Widget.Controller(this._model, service, this);
    
    // connect the renderer to the model
    this._renderer.connect(this._model);
    
};


flyui.flyatlas.Widget.prototype.getAssaysByAffyProbeId = function( id ) {
    // pass through to controller
    this._controller.getAssaysByProbeId(id);
}


flyui.flyatlas.Widget.prototype.getAssaysByGene = function( gene ) {
	// pass through to controller
	this._controller.getAssaysByGene(gene);
}


/*
 * ----------------------------------------------------------------
 *                             CONTROLLER
 * ----------------------------------------------------------------
 */


/**
 * @class
 */
flyui.flyatlas.Widget.Controller = function( model, service, widget ) {
    this._init(model, service, widget);
};


/**
 * @private
 * @type flyui.mvcutils.GenericModel2
 */
flyui.flyatlas.Widget.Controller.prototype._model = null;


/**
 * @private
 * @type flyui.flyatlas.Service
 */
flyui.flyatlas.Widget.Controller.prototype._service = null;


/**
 * @private
 * @type flyui.flyatlas.Widget
 */
flyui.flyatlas.Widget.Controller.prototype._parent = null;


flyui.flyatlas.Widget.Controller.prototype._init = function( model, service, widget ) {
    this._model = model;
    this._service = service;
    this._parent = widget;
};


/**
 * @param {String} affyId
 */
flyui.flyatlas.Widget.Controller.prototype.getAssaysByAffyProbeId = function( affyId ) {
    // pass through to private implementation
    this._getAssaysByAffyProbeId(affyId, this._getAssaysSuccess(), this._getAssaysFailure());
};


/**
 * @param {String} flybaseId
 */
flyui.flyatlas.Widget.Controller.prototype.getAssaysByGene = function( gene ) {
    // pass through to private implementation
    this._getAssaysByGene(gene, this._getAssaysSuccess(), this._getAssaysFailure());
};


/**
 * @private
 * @param {String} affyId
 * @param {Function} success
 * @param {Function} failure
 */
flyui.flyatlas.Widget.Controller.prototype._getAssaysByAffyProbeId = function( affyId, success, failure ) {
    flyui.debug("in _getAssaysByProbeId, affyId: "+affyId);
    this._model.set("RESULTS", null);
    this._model.set("QUERY", affyId);
    this._model.set("MODE", "PROBE");
    this._model.set("STATE", "PENDING");
    this._service.getAssaysByAffyProbeId(affyId, success, failure);
};

/**
 * @private
 * @param {String} flybaseId
 * @param {Function} success
 * @param {Function} failure
 */
flyui.flyatlas.Widget.Controller.prototype._getAssaysByGene = function( gene, success, failure ) {
    flyui.debug("in _getAssaysByGene, flybaseId: "+gene.flybaseId);
    this._model.set("RESULTS", null);
    this._model.set("QUERY", gene);
    this._model.set("MODE", "GENE");
    this._model.set("STATE", "PENDING");
    this._service.getAssaysByFlybaseGeneId(gene.flybaseID, success, failure);
};


/**
 * @private
 * @type Function
 */
flyui.flyatlas.Widget.Controller.prototype._getAssaysSuccess = function() {
    var self = this;
    return function( groups ) {
        self._model.set("RESULTS", groups);
        self._model.set("STATE", "READY");
    }
};


/**
 * @private
 * @type Function
 */
flyui.flyatlas.Widget.Controller.prototype._getAssaysFailure = function() {
    var self = this;
    return function( response ) {
        flyui.err("request failed: "+response.status+" "+response.statusText);
        self._model.set("MESSAGE", "there was an error retrieving data from the server, see the logs for more info");
        self._model.set("STATE", "SERVERERROR");
    }
};




/** 
 * @type Object
 */
flyui.flyatlas.Widget.modelDefinition = {

    properties : [ "STATE", "RESULTS", "MESSAGE", "QUERY", "MODE" ],
    
    values : {
        "STATE" : [ "READY", "PENDING", "SERVERERROR", "UNEXPECTEDERROR" ],
        "MODE" : [ "PROBE", "GENE" ]
    },
    
    initialize : function( data ) {
        data["STATE"] = "READY";
        data["RESULTS"] = null;
        data["MESSAGE"] = null;
        data["QUERY"] = null;
        data["MODE"] = null;
    }

};


/*
 * ----------------------------------------------------------------
 *                             DEFAULT RENDERER
 * ----------------------------------------------------------------
 */
 
 
/**
 * @class
 */
flyui.flyatlas.Widget.DefaultRenderer = function() {};

/** @private */
flyui.flyatlas.Widget.DefaultRenderer.prototype._canvas = null;

/** @private */
flyui.flyatlas.Widget.DefaultRenderer.prototype._pendingPane = null;

/** @private */
flyui.flyatlas.Widget.DefaultRenderer.prototype._resultsPane = null;

/** @private */
flyui.flyatlas.Widget.DefaultRenderer.prototype._resultsSummaryPane = null;

/** @private */
flyui.flyatlas.Widget.DefaultRenderer.prototype._messagePane = null;


/**
 * @param {Element} canvas
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
//    this._canvas = canvas;
    this._canvas = $(canvas);
    this._initCanvas();
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._initCanvas = function() {
    flyui.debug("_initCanvas");
    
    var canvas = this._canvas;
    
    // setup pending pane
//    this._pendingPane = document.createElement("p");
//    this._pendingPane.innerHTML = "pending...";
//    this._canvas.appendChild(this._pendingPane);
//    YAHOO.util.Dom.addClass(this._pendingPane, "pendingPane");
//    flyui.mvcutils.hide(this._pendingPane);
    var pp = $("<p class='pendingPane'>pending...</p>").hide();
    canvas.append(pp);
    this._pendingPane = pp;

    // setup results summary pane
//    this._resultsSummaryPane = document.createElement("p");
//    this._resultsSummaryPane.innerHTML = "this should never be displayed";
//    this._canvas.appendChild(this._resultsSummaryPane);
//    YAHOO.util.Dom.addClass(this._resultsSummaryPane, "resultsSummaryPane");
//    flyui.mvcutils.hide(this._resultsSummaryPane);
    var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
    canvas.append(rsp);
    this._resultsSummaryPane = rsp;
    
    // setup results pane
//    this._resultsPane = document.createElement("div");
//    this._canvas.appendChild(this._resultsPane);
//    YAHOO.util.Dom.addClass(this._resultsPane, "resultsPane");
//    flyui.mvcutils.hide(this._resultsPane);
    var rp = $("<div class='resultsPane'></div>").hide();
    canvas.append(rp);
    this._resultsPane = rp;

    // message pane
//    this._messagePane = document.createElement("p");
//    this._messagePane.innerHTML = "this should never be displayed";
//    this._canvas.appendChild(this._messagePane);
//    YAHOO.util.Dom.addClass(this._messagePane, "messagePane");
//    flyui.mvcutils.hide(this._messagePane); 
    var mp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
    canvas.append(mp);
    this._messagePane = mp;    

};


/**
 * @param {flyui.mvcutils.GenericModel2} model
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype.connect = function( model ) {
    model.subscribeAll(this._onModelChanged, this);
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onModelChanged = function( type, args, self ) {
    var handlers = {
        "STATE":"_onStateChanged",
        "QUERY":"_onQueryChanged",
        "RESULTS":"_onResultsChanged",
        "MESSAGE":"_onMessageChanged", 
        "MODE":"_onModeChanged"
    };
    var handler = handlers[type];
    flyui.debug("handler: "+handler);
    // call the handler
    self[handler](args[0], args[1], args[2]);
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onQueryChanged = function( from, to, get ) {
    // do nothing, we will access the value later
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onModeChanged = function( from, to, get ) {
    // do nothing, we will access the value later
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {

    if ( to == "PENDING" ) {
        this._pendingPane.show();
        this._messagePane.empty().hide();
        this._resultsSummaryPane.hide();
        this._resultsPane.hide();
    }
    else if ( to == "READY" ) {
        this._pendingPane.hide();
        this._messagePane.hide(); // hide for now, not needed yet
        this._resultsSummaryPane.show();
        this._resultsPane.show();         
    } 
    else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
        this._pendingPane.hide();
        this._messagePane.show();
        this._resultsSummaryPane.hide();
        this._resultsPane.hide();         
    } 
    else {
        // this should never happen
        throw new flyui.flyatlas.UnexpectedStateError("Invalid state: "+to);
    }
    
};

/**
 * @class
 * An exception thrown if an unexpected state is encountered in the widget model.
 * @param {String} message
 */
flyui.flyatlas.UnexpectedStateError = function( message ) {
    this.name = "flyui.flyatlas.UnexpectedStateError";
    this.message = message;
};



/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onResultsChanged = function( from, to, get ) {
    
    flyui.debug("results changed: "+to);
    
    if (to == null) {
        flyui.debug("empty results summary pane");
        this._resultsSummaryPane.empty();
        flyui.debug("empty results pane");
        this._resultsPane.empty();
    }
    else {

        var query = get("QUERY"); // fetch from model
        var mode = get("MODE"); // fetch from model
        
        flyui.debug("render results summary");
        this._renderResultsSummary(mode, query, to.length);

        flyui.debug("render results");
        this._renderResults(to);        
        
    }    
    
};


/**
 * @private
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._onMessageChanged = function( from, to, get ) {
    this._messagePane.html(to);
};


/**
 * @private
 * Render the results summary pane.
 * @param {String} query the user's query
 * @param {Number} count number of results found
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._renderResultsSummary = function( mode, query, count ) {
    var content = "showing ";
    content += count;
    content += " matching probe";
    content += (count == 0 || count > 1) ? "s " : " ";
    content += "from <a href='http://www.flyatlas.org'>www.flyatlas.org</a> for ";
    if (mode == "PROBE") {
		content += "probe "+query;    	
    } else if (mode == "GENE") {
    	content += "gene <strong>"+query.symbols[0]+"</strong>...";
    } else {
    	flyui.err("unexpected mode: "+mode);
    }
    this._resultsSummaryPane.html(content);
}


/**
 * @private
 * Render the results pane.
 * @param {Array<flyui.flyatlas.AssayGroup>} results
 */
flyui.flyatlas.Widget.DefaultRenderer.prototype._renderResults = function( results ) {
    
    var pane = this._resultsPane;
    
    var content = "<table class='resultsTable'>";
 
//    flyui.debug("generate header content");  
    
    content += "<thead><tr><th>probe</th><th>tissue</th><th>mRNA signal</th><th>present call</th><th>enrichment</th><th>affy call</th></thead>";

    for (var j=0; j<results.length; j++) {
        var result = results[j];
        content += "<tbody>";
        for (var i=0; i<flyui.flyatlas.tissues.length; i++) {
            var tissue = flyui.flyatlas.tissues[i];
//            flyui.debug("row for tissue "+tissue);
            var assay = result[tissue];
            var classnames = "";
            if (tissue == "whole") {
            	classnames = "top";
            } else {
	            if (assay.change == "Up") {
	            	if (assay.ratio > 2) {
		            	classnames = "callUp xx";
	            	} else {
		            	classnames = "callUp x";
	            	}
	            } else if (assay.change == "Down") {
	            	if (assay.ratio < 0.5) {
		            	classnames = "callDown xx";
	            	} else {
		            	classnames = "callDown x";
	            	}
	            } else {
	            	classnames = "callNone";
	            }
            }
            content += "<tr class='"+classnames+"'>";
//            content += (tissue == "whole") ? "<tr class='top'>" : "<tr>";
//            flyui.debug("first cell (probe id)");
            content += (tissue == "whole") ? "<td rowspan='15'><strong><a href='http://flyatlas.org/probeset.cgi?name="+result.affy_id+"'>"+result.affy_id+"</a></strong></td>" : "" ;
//            flyui.debug("second cell (tissue)");
            content += "<td>"+tissue+"</td>" ;
//            flyui.debug("third cell (signal)");
            content += "<td>"+assay.mean+" ± "+assay.sem+"</td>" ;
//            flyui.debug("fourth cell (present)");
            content += "<td>"+assay.present+" of 4</td>" ;
//            flyui.debug("fifth cell (enrichment)");
            content += (tissue != "whole") ? "<td>"+assay.ratio+"</td>" : "<td> - </td>" ;
//            flyui.debug("sixth cell (call)");
            content += (tissue != "whole") ? "<td>"+assay.change+"</td>" : "<td> - </td>" ;
            content += "</tr>";
        }
        content += "</tbody>";                
    }    
    
    content += "</table>";

//    flyui.debug(content);
    
    pane.append($(content));

};

